package com.gitee.magic.jdbc.persistence.support;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.gitee.magic.context.PropertyConverterEditor;
import com.gitee.magic.core.annotations.Column;
import com.gitee.magic.core.annotations.Transient;
import com.gitee.magic.core.converter.PropertyConverter;
import com.gitee.magic.core.exception.ApplicationException;
import com.gitee.magic.core.utils.ChangeCharUtils;
import com.gitee.magic.core.utils.ContextSupportType;
import com.gitee.magic.core.utils.StringUtils;
import com.gitee.magic.jdbc.persistence.EntityDefinitionException;
import com.gitee.magic.jdbc.persistence.EntityObject;
import com.gitee.magic.jdbc.persistence.EntityProperty;
import com.gitee.magic.jdbc.persistence.EntityPropertyStubPrimaryKey;
import com.gitee.magic.jdbc.persistence.annotation.DuplicateKeyUpdated;
import com.gitee.magic.jdbc.persistence.annotation.Entity;
import com.gitee.magic.jdbc.persistence.annotation.Id;
import com.gitee.magic.jdbc.persistence.annotation.MappedSuperclass;
import com.gitee.magic.jdbc.persistence.annotation.Table;

/**
 * @author start
 */
public class EntityDefinitionDelegate {

	private static final Logger LOGGER = LoggerFactory.getLogger(EntityDefinitionDelegate.class);
	
	public  static EntityObject parse(Class<?> prototype) throws EntityDefinitionException {
		EntityObject eObject = new EntityObject();
		// 获取实体名称
		Entity entity = prototype.getAnnotation(Entity.class);
		if (entity != null) {
			eObject.setName(entity.value());
		}else{
			throw new EntityDefinitionException("ORM实体类："+prototype+"--未添加@Entity注解！");
		}
		// 获取表名
		Table table = prototype.getAnnotation(Table.class);
		if (table != null) {
			eObject.setTableName(table.value());
		}else{
			TableName tableName = prototype.getAnnotation(TableName.class);
			if (tableName != null) {
				eObject.setTableName(tableName.value());
			}else{
				throw new EntityDefinitionException("Class<"+prototype+">,未定义@Table或@TableName注解，找不到映射的表名");
			}
		}
		Class<?> classes = prototype;
		while (classes.isAnnotationPresent(Entity.class)||
				classes.isAnnotationPresent(MappedSuperclass.class)) {
			Field[] fields=classes.getDeclaredFields();
			for(Field field:fields) {
				if(Modifier.isFinal(field.getModifiers())||Modifier.isStatic(field.getModifiers())) {
					continue;
				}
				String fieldName=field.getName();
				// 不生成当前表字段跳过
				Transient trans = field.getAnnotation(Transient.class);
				if (trans != null) {
					continue;
				}
				Class<?> dataType = field.getType();
				// 参数验证
				PropertyConverter convert=field.getAnnotation(PropertyConverter.class);
				if(convert!=null) {
					PropertyConverterEditor.putCustomConverterType(prototype, fieldName, convert.value());
				}else {
					convert=field.getType().getAnnotation(PropertyConverter.class);
					if(convert!=null) {
						PropertyConverterEditor.putBasicConverterType(field.getType(),convert.value());
					}else {
						if (!PropertyConverterEditor.isSupportConverter(dataType)) {
							if(entity.converter()) {
								throw new EntityDefinitionException("Class<" + prototype + ">,字段:" + fieldName + "不支持"+dataType+"类型，特殊类型请定义转写类");
							}
						}
					}
				}
				
				String tableFieldName = "";
				EntityProperty property = null;
				Id idA = field.getAnnotation(Id.class);
				if (idA != null) {
					if (!ContextSupportType.isSupportTypeCheckByPrimaryKey(dataType)) {
						throw new EntityDefinitionException("Class<" + prototype + ">,@Id注解的字段:" + fieldName + "不支持"+dataType+"类型");
					}
					property=new EntityPropertyStubPrimaryKey(idA.value());
				}else{
					property=new EntityProperty();
				}
				Column column = field.getAnnotation(Column.class);
				if (column != null) {
					tableFieldName = column.value();
				}else {
					tableFieldName = fieldName;
					if(table!=null) {
						if(table.fieldNameToUnderline()) {
							tableFieldName =ChangeCharUtils.camelToUnderline(tableFieldName, 1);
						}
					}else {
						TableField tableField = field.getAnnotation(TableField.class);
						if (tableField != null) {
							if(!StringUtils.isEmpty(tableField.value())) {
								tableFieldName = tableField.value();
							}
						}
					}
				}
				PropertyDescriptor pd=null;
				try {
					pd = new PropertyDescriptor(fieldName, classes);
				} catch (IntrospectionException e) {
					if(LOGGER.isErrorEnabled()) {
						LOGGER.error("Class[{}],Type:[{}],Field:[{}],未获取到get,set方法",prototype,field.getType(),fieldName);
					}
					throw new ApplicationException(e);
				}
				property.setDescriptor(pd);
				property.setDataType(dataType);
				property.setFieldName(fieldName);
				if(field.isAnnotationPresent(DuplicateKeyUpdated.class)) {
					DuplicateKeyUpdated duplicateKeyUpdated = field.getAnnotation(DuplicateKeyUpdated.class);
					if(StringUtils.isEmpty(duplicateKeyUpdated.expression())) {
						property.setDuplicateKeyUpdated("VALUES("+tableFieldName+")");
					}else {
						property.setDuplicateKeyUpdated(duplicateKeyUpdated.expression());
					}
				}
				// 如果未设置映射的表字段名则默认跟字段名相同
//				tableFieldName="".equals(tableFieldName.trim()) ? table.fieldPrefix()+property.getFieldName() : table.fieldPrefix()+tableFieldName;
				property.setTableFieldName(tableFieldName);
				if(property instanceof EntityPropertyStubPrimaryKey){
					eObject.setEntityPropertyStubPrimaryKey((EntityPropertyStubPrimaryKey)property);
				}else{
					eObject.getMembers().add(property);
				}
			}
			classes = classes.getSuperclass();
		}
		return eObject;
	}
	
}
